/* 
The NIST RCS (Real-time Control Systems) 
library is public domain software, however it is preferred
that the following disclaimers be attached.

Software Copywrite/Warranty Disclaimer

This software was developed at the National Institute of Standards and
Technology by employees of the Federal Government in the course of their
official duties. Pursuant to title 17 Section 105 of the United States
Code this software is not subject to copyright protection and is in the
public domain. NIST Real-Time Control System software is an experimental
system. NIST assumes no responsibility whatsoever for its use by other
parties, and makes no guarantees, expressed or implied, about its
quality, reliability, or any other characteristic. We would appreciate
acknowledgement if the software is used. This software can be
redistributed and/or modified freely provided that any derivative works
bear some notice that they are derived from it, and any modified
versions bear some notice that they have been modified.



 */
package diagapplet.CodeGen;

import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.StringTokenizer;
import rcs.utils.StackTracePrinter;

class C_Generator {

    static public boolean debug_on = false;
    static public boolean display_on = false;
    static public diagapplet.utils.URLLoadInfoPanelInterface m_loadingPanel = null;

    static public void DebugPrint(String s) {
        try {
            if (!debug_on) {
                return;
            }
            Throwable t = new Throwable();
            System.out.println(StackTracePrinter.ThrowableToShortList(t) + " " + s);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static public String Get_C_FormatFunction(String selected_classes[], CodeGenCommonInterface2 cgc) {
        try {
            String format_function_name_base = cgc.GetFormatFunctionNameBase(selected_classes);
            if (null == format_function_name_base) {
                return null;
            }
            String c_format_function_name = format_function_name_base + "_c_format";
            return c_format_function_name;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    static public String ConvertCppTokToC_Tok(String cpp_tok, CodeGenCommonInterface2 cgc) {
        try {
            SplitInfoToken spi = new SplitInfoToken(cpp_tok);
            boolean is_class = cgc.CheckForCppClass(spi.cpp_type);
            boolean is_enum = cgc.CheckForCppEnum(spi.cpp_type);
            String cpp_type = spi.cpp_type;
            String c_type = cpp_type;
            String c_tok;
            if (is_class) {
                if (cpp_type.startsWith("class ")) {
                    cpp_type = cpp_type.substring(6);
                } else if (cpp_type.startsWith("struct ")) {
                    cpp_type = cpp_type.substring(6);
                }
                c_type = "nml_" + cpp_type + "_c_t";
            } else if ((is_enum || spi.enum_flag) && !cpp_type.startsWith("enum ")) {
                c_type = "enum " + cpp_type;
            } else if (c_type.equals("bool")) {
                c_type = "nml_c_bool_t";
            }
            if (spi.array_suffix != null) {
                c_tok = c_type + " " + spi.variable_name + spi.array_suffix;
            } else {
                c_tok = c_type + " " + spi.variable_name;
            }
            if (debug_on) {
                DebugPrint("ConvertCppTokToC_Tok(cpp_tok=" + cpp_tok + ") produced c_tok=" + c_tok);
            }
            return c_tok;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void GenerateC_UpdateFunction(String class_name,
            CodeGenCommonInterface2 cgc,
            java.util.Hashtable sin) {
        StructureTypeInfo type_info;
        try {
            cgc.GenerateC_StartOfFile();

            type_info = (StructureTypeInfo) sin.get(class_name);
            if (null == type_info) {
                return;
            }
            if (cgc.IsNonUpdatebleClass(type_info)) {
                return;
            }
            cgc.WriteOutput("\n/*\n*\tNML/CMS Update function for " + class_name + "\n");
            cgc.WriteOutput("*\tAutomatically generated by NML CodeGen Java Applet.\n");
            cgc.WriteOutput("*/\n");
            cgc.WriteOutput("void cms_" + StringFuncs.replace_white_space(class_name) + "_update(struct cms_c_struct *cms, nml_" + class_name + "_c_t *x)\n{\n");
            if (null == type_info.C_UpdateFunction) {
                cgc.CreateC_UpdateFunction(type_info);
            }
            if (null != type_info.C_UpdateFunction) {
                cgc.WriteOutput(type_info.C_UpdateFunction);
            }
            cgc.WriteOutput("\n}\n\n");
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("Error Generating C Update function for " + class_name);

        }
    }

    // @SuppressWarnings("unchecked")
    static public void WriteC_UpdateFunctionProtos(String selected_classes[], CodeGenCommonInterface2 cgc) {
        try {
            Vector class_prototypes = new Vector();

            for (int i = 0; i < selected_classes.length; i++) {
                StructureTypeInfo type_info = (StructureTypeInfo) ModuleInfo.m_structInfoByNameHashTable.get(selected_classes[i]);
                boolean already_prototyped = false;
                if (type_info.DerivedFrom != null) {
                    already_prototyped = false;
                    for (int j = 0; j < class_prototypes.size(); j++) {
                        String prototype_class = (String) class_prototypes.elementAt(j);
                        if (prototype_class.equals(type_info.DerivedFrom)) {
                            already_prototyped = true;
                            break;
                        }
                    }
                    if (!already_prototyped && !cgc.IsNonUpdatebleClass(type_info) && !type_info.DerivedFrom.equals("NMLmsg") && !type_info.DerivedFrom.equals("RCS_STAT_MSG") && !type_info.DerivedFrom.equals("RCS_STAT_MSG_V2") && !type_info.DerivedFrom.equals("RCS_CMD_MSG")) {
                        cgc.WriteOutput("void cms_" + StringFuncs.replace_white_space(type_info.UnqualifiedDerivedFrom) + "_update(struct cms_c_struct *cms, nml_" + type_info.DerivedFrom + "_c_t *x);\n");
                        class_prototypes.addElement(type_info.DerivedFrom);
                    }
                }
                StringTokenizer info_tokenizer = new StringTokenizer(type_info.PreFinalPassInfo, ";");
                while (info_tokenizer.hasMoreTokens()) {
                    String info_token = info_tokenizer.nextToken();
                    SplitInfoToken sit = new SplitInfoToken(info_token);
                    boolean is_class = cgc.CheckForCppClass(sit.cpp_type);
                    if (is_class) {
                        already_prototyped = false;
                        for (int j = 0; j < class_prototypes.size(); j++) {
                            String prototype_class = (String) class_prototypes.elementAt(j);
                            if (prototype_class.equals(sit.cpp_type)) {
                                already_prototyped = true;
                                break;
                            }
                        }
                        if (!already_prototyped) {
                            cgc.WriteOutput("void cms_" + StringFuncs.replace_white_space(sit.cpp_type) + "_update(struct cms_c_struct *cms, nml_" + sit.cpp_type + "_c_t *x);\n");
                            class_prototypes.addElement(sit.cpp_type);
                        }
                    }
                }
                String class_name = type_info.Name;
                already_prototyped = false;
                for (int j = 0; j < class_prototypes.size(); j++) {
                    String prototype_class = (String) class_prototypes.elementAt(j);
                    if (prototype_class.equals(class_name)) {
                        already_prototyped = true;
                        break;
                    }
                }
                if (!already_prototyped) {
                    cgc.WriteOutput("void cms_" + StringFuncs.replace_white_space(class_name) + "_update(struct cms_c_struct *cms, nml_" + class_name + "_c_t *x);\n");
                    class_prototypes.addElement(class_name);
                }
                if (null != m_loadingPanel && display_on) {
                    m_loadingPanel.set_bytes_read(m_loadingPanel.get_bytes_read() + 1);
                    m_loadingPanel.force_repaint(500);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // @SuppressWarnings("unchecked")
    static public void GenerateC_PrototypesHeader(String selected_classes[],
            CodeGenCommonInterface2 cgc,
            String currentOutputFileName,
            java.util.Hashtable enumInfoHashTable) {
        try {
            String symbol_lookup_function_name = null;
            if (debug_on) {

                DebugPrint("CodeGenCommon.GenerateC_PrototypesHeader() called.");
                new Throwable().printStackTrace(System.out);
            }
            if (debug_on) {
                if (null == selected_classes) {
                    DebugPrint("CodeGenCommon.GenerateC_PrototypesHeader() : selected_classes = null;");
                } else {
                    DebugPrint("CodeGenCommon.GenerateC_PrototypesHeader() : selected_classes.length = " + selected_classes.length);
                }
            }

            if (selected_classes.length < 1) {
                return;
            }
            if (debug_on) {
                DebugPrint("selected_classes[0]=" + selected_classes[0]);
            }
            StructureTypeInfo type_info = (StructureTypeInfo) ModuleInfo.m_structInfoByNameHashTable.get(selected_classes[0]);
            if (debug_on) {
                DebugPrint("type_info=" + type_info);
                DebugPrint("type_info.first_module_used_in=" + type_info.first_module_used_in);
            }
            cgc.WriteOutput("/*\n*\tNew C++ Header  File starts here.\n*\tThis file should be named " + currentOutputFileName + "\n*/\n\n");
            cgc.WriteOutput("#ifndef " + currentOutputFileName.replace('.', '_') + "_included\n");
            cgc.WriteOutput("#define " + currentOutputFileName.replace('.', '_') + "_included\n\n");
            cgc.WriteOutput("/* Include all NML and CMS functions */\n#include \"nmlcms_c.h\"\n\n");
            cgc.WriteOutput("/* Include the other header files that contain message definitions we might need. */\n");
            for (int i = 0; i < ModuleInfo.headerFiles.size(); i++) {
                String header = (String) ModuleInfo.headerFiles.elementAt(i);
                int pindex = header.indexOf('.');
                String headerbase = header;
                if (pindex > 0) {
                    headerbase = header.substring(0, pindex);
                }
                String c_n_header = headerbase + "_c_n.h";
                if (c_n_header.equals(currentOutputFileName)) {
                    continue;
                }
                cgc.WriteOutput("#include \"" + c_n_header + "\"\n");
            }
            cgc.WriteOutput("\n");

            String c_format_function_name = Get_C_FormatFunction(selected_classes, cgc);
            if (null == c_format_function_name) {
                throw new Exception("c_format_function_name is NULL");
            }
            String swig_module_name = c_format_function_name.substring(0, c_format_function_name.length() - 9);

            if (!CodeGenCommon.no_swig) {
                cgc.WriteOutput("/* SWIG (Simplified Wrapper and Interface Generator) support. */\n");
                cgc.WriteOutput("/* see http://www.swig.org */\n");
                cgc.WriteOutput("#ifdef SWIG\n");

                cgc.WriteOutput("%module " + swig_module_name + "_nml\n");
                cgc.WriteOutput("%{\n");
                cgc.WriteOutput("#include \"" + currentOutputFileName + "\"\n");
                cgc.WriteOutput("#include \"nmlcms_c.h\"\n");
                cgc.WriteOutput("%}\n");
                cgc.WriteOutput("#endif\n");
                cgc.WriteOutput("/* end of #ifdef SWIG */\n");

                cgc.WriteOutput("\n");
            }


            cgc.WriteOutput("#ifndef SWIG\n");
            cgc.WriteOutput("#ifdef __cplusplus\n");
            cgc.WriteOutput("extern \"C\" {\n");
            cgc.WriteOutput("#endif\n");
            cgc.WriteOutput("#endif\n");
            cgc.WriteOutput("/* end of #ifndef SWIG */\n");
            cgc.WriteOutput("\n");


            try {
                if (null != enumInfoHashTable && !CodeGenCommon.no_enums) {
                    cgc.WriteOutput("\n/* Create C versions of the Enumeration types. */\n");
                    Enumeration enum_info_types = enumInfoHashTable.elements();
                    while (enum_info_types.hasMoreElements()) {
                        EnumTypeInfo enum_info = (EnumTypeInfo) enum_info_types.nextElement();
                        if (null == enum_info) {
                            continue;
                        }
                        if (null == enum_info.reverse_hashtable) {
                            continue;
                        }
                        if (enum_info.reverse_hashtable.size() < 1) {
                            continue;
                        }
                        cgc.WriteOutput("#ifndef ENUM_" + enum_info.Name + "_DEFINED\n");
                        cgc.WriteOutput("#define ENUM_" + enum_info.Name + "_DEFINED\n");
                        cgc.WriteOutput("\nenum " + enum_info.Name + " {\n");

                        Enumeration enum_keys = enum_info.reverse_hashtable.keys();
                        while (enum_keys.hasMoreElements()) {
                            String key = (String) enum_keys.nextElement();
                            int val = -1;
                            try {
                                Integer Ival = (Integer) enum_info.reverse_hashtable.get(key);
                                val = Ival.intValue();
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                            if (enum_keys.hasMoreElements()) {
                                cgc.WriteOutput("\t" + key + "=" + val + ",\n");
                            } else {
                                cgc.WriteOutput("\t" + key + "=" + val + "\n");
                            }
                        }
                        cgc.WriteOutput("};\n");
                        cgc.WriteOutput("#endif\n/* end of #ifdef ENUM_" + enum_info.Name + "_DEFINED */\n");
                        cgc.WriteOutput("\n");

                    }
                }
                cgc.WriteOutput("\n");
            } catch (Exception e) {
                e.printStackTrace();
            }

            cgc.WriteOutput("/* Redefine the message classes as C typedef structs. */\n");
            for (int i = 0; i < selected_classes.length; i++) {
                if (debug_on) {
                    DebugPrint("selected_classes[" + i + "]=" + selected_classes[i]);
                }
                type_info = (StructureTypeInfo) ModuleInfo.m_structInfoByNameHashTable.get(selected_classes[i]);
                String def1 = "";
                StructureTypeInfo ti = type_info;
                while (ti != null) {
                    if (null != ti.PreFinalPassInfo) {
                        def1 = ti.PreFinalPassInfo + ";" + def1;
                    }
                    if (ti.DerivedFrom != null) {
                        ti = (StructureTypeInfo) ModuleInfo.m_structInfoByNameHashTable.get(ti.DerivedFrom);
                    } else {
                        ti = null;
                    }
                }
                cgc.WriteOutput("\n");
                if (type_info.Id > 0) {
                    cgc.WriteOutput("#ifndef " + type_info.Name + "_TYPE\n");
                    cgc.WriteOutput("#define " + type_info.Name + "_TYPE\t" + type_info.Id + "\n");
                    cgc.WriteOutput("#endif\n");

                    if (type_info.type_id_string != null
                            && !type_info.type_id_string.equals(type_info.Name + "_TYPE")
                            && Character.isLetter(type_info.type_id_string.charAt(0))) {
                        cgc.WriteOutput("#ifndef " + type_info.type_id_string + "\n");
                        cgc.WriteOutput("#define " + type_info.type_id_string + "\t" + type_info.Id + "\n");
                        cgc.WriteOutput("#endif\n");
                    }
                    cgc.WriteOutput("\n");
                }
                cgc.WriteOutput("typedef struct {\n");
                StringTokenizer st = new StringTokenizer(def1, ";");
                while (st.hasMoreTokens()) {
                    String tok = st.nextToken();
                    String c_tok = ConvertCppTokToC_Tok(tok, cgc);
                    if (null != c_tok) {
                        cgc.WriteOutput("\t" + c_tok + ";\n");
                    }
                }
                cgc.WriteOutput("} nml_" + type_info.Name + "_c_t;\n");
            }

            cgc.WriteOutput("\n");

            cgc.WriteOutput("#ifndef SWIG\n");
            cgc.WriteOutput("\n");

            cgc.WriteOutput("/* Update function prototypes. */\n");
            WriteC_UpdateFunctionProtos(selected_classes, cgc);

            cgc.WriteOutput("\n");
            cgc.WriteOutput("#endif\n");
            cgc.WriteOutput("/* end of #ifndef SWIG */\n");
            cgc.WriteOutput("\n");


            String namelist_name = null;
            String sizelist_name = null;
            String idlist_name = null;
            if (null != c_format_function_name) {
                if (!c_format_function_name.toUpperCase().endsWith("FORMAT")) {
                    symbol_lookup_function_name = c_format_function_name;
                } else {
                    symbol_lookup_function_name = c_format_function_name.substring(0, c_format_function_name.length() - 6);
                }
                if (symbol_lookup_function_name.endsWith("_")) {
                    symbol_lookup_function_name += "symbol_lookup";
                } else {
                    symbol_lookup_function_name += "_symbol_lookup";
                }

                idlist_name = c_format_function_name.substring(0, c_format_function_name.length() - 6);
                idlist_name += "id_list";
                sizelist_name = c_format_function_name.substring(0, c_format_function_name.length() - 6);
                sizelist_name += "size_list";
                namelist_name = c_format_function_name.substring(0, c_format_function_name.length() - 6);
                namelist_name += "name_list";
            }

            cgc.WriteOutput("\n");
            int longest_name_length = 0;
            int number_of_names = 0;
            for (int i = 0; i < selected_classes.length; i++) {
                StructureTypeInfo typeInfo = (StructureTypeInfo) ModuleInfo.m_structInfoByNameHashTable.get(selected_classes[i]);
                if (null == typeInfo) {
                    continue;
                }
                if (typeInfo.Id <= 0 || typeInfo.DerivedFrom == null) {
                    continue;
                }
                number_of_names++;
                if (selected_classes[i].length() > longest_name_length) {
                    longest_name_length = selected_classes[i].length();
                }
            }

            if (null != namelist_name && null != idlist_name && null != sizelist_name && null != symbol_lookup_function_name) {
                cgc.WriteOutput("#ifndef MAX_" + namelist_name.substring(0, namelist_name.length() - 5).toUpperCase() + "_LENGTH\n");
                cgc.WriteOutput("#define MAX_" + namelist_name.substring(0, namelist_name.length() - 5).toUpperCase() + "_LENGTH " + (longest_name_length + 1) + "\n");
                cgc.WriteOutput("#endif\n");
                cgc.WriteOutput("#ifndef " + namelist_name.toUpperCase() + "_LENGTH\n");
                cgc.WriteOutput("#define " + namelist_name.toUpperCase() + "_LENGTH " + (number_of_names + 1) + "\n");
                cgc.WriteOutput("#endif\n");
                cgc.WriteOutput("\n");
                cgc.WriteOutput("\n/* This list must be in alphabetical order and the three lists must correspond. */\n");
                cgc.WriteOutput("extern const char " + namelist_name + "[" + namelist_name.toUpperCase() + "_LENGTH][MAX_" + namelist_name.substring(0, namelist_name.length() - 5).toUpperCase() + "_LENGTH];\n");
                cgc.WriteOutput("extern const NMLTYPE " + idlist_name + "[" + namelist_name.toUpperCase() + "_LENGTH];\n");
                cgc.WriteOutput("extern const size_t " + sizelist_name + "[" + namelist_name.toUpperCase() + "_LENGTH];\n");
                cgc.WriteOutput("extern const char *" + symbol_lookup_function_name + "(long type);\n");
                cgc.WriteOutput("\n");
            }

            try {
                if (null != enumInfoHashTable && !CodeGenCommon.no_enums) {
                    cgc.WriteOutput("\n/* Enumerated Type Constants */\n");
                    Enumeration enum_info_types = enumInfoHashTable.elements();
                    while (enum_info_types.hasMoreElements()) {
                        EnumTypeInfo enum_info = (EnumTypeInfo) enum_info_types.nextElement();
                        if (null == enum_info) {
                            continue;
                        }
                        if (null == enum_info.reverse_hashtable) {
                            continue;
                        }
                        if (enum_info.reverse_hashtable.size() < 1) {
                            continue;
                        }
                        cgc.WriteOutput("\n/* " + enum_info.Name + " */\n");
                        int maxenumvalstringlength = 0;
                        int numenumvals = 0;

                        Enumeration enum_keys = enum_info.reverse_hashtable.keys();
                        Vector sorted_enum_key_vector = new Vector();
                        while (enum_keys.hasMoreElements()) {
                            String key = (String) enum_keys.nextElement();
                            numenumvals++;
                            if (maxenumvalstringlength < key.length()) {
                                maxenumvalstringlength = key.length();
                            }
                            boolean keyadded = false;
                            for (int ki = 0; ki < sorted_enum_key_vector.size(); ki++) {
                                String compareKey = (String) sorted_enum_key_vector.elementAt(ki);
                                if (key.compareTo(compareKey) < 0) {
                                    sorted_enum_key_vector.insertElementAt(key, ki);

                                    keyadded = true;
                                    break;
                                }
                            }
                            if (!keyadded) {
                                sorted_enum_key_vector.addElement(key);
                            }
                        }
                        String enumlistname =
                                /// c_format_function_name.substring(0,c_format_function_name.length()-6)+
                                "enum_" + enum_info.Name;
                        cgc.WriteOutput("#ifndef MAX_" + enumlistname.toUpperCase() + "_C_STRING_LENGTH\n");
                        cgc.WriteOutput("#define MAX_" + enumlistname.toUpperCase() + "_C_STRING_LENGTH "
                                + (maxenumvalstringlength + 1) + "\n");
                        cgc.WriteOutput("#endif\n\t/* MAX_" + enumlistname.toUpperCase() + "_C_STRING_LENGTH */\n");
                        cgc.WriteOutput("#ifndef " + enumlistname.toUpperCase() + "_C_LENGTH\n");
                        cgc.WriteOutput("#define " + enumlistname.toUpperCase() + "_C_LENGTH " + (numenumvals + 1) + "\n");
                        cgc.WriteOutput("#endif\n\t/* " + enumlistname.toUpperCase() + "_C_LENGTH */\n");
                        cgc.WriteOutput("\nextern const char " + enumlistname + "_c_string_list[" + enumlistname.toUpperCase()
                                + "_C_LENGTH][MAX_" + enumlistname.toUpperCase() + "_C_STRING_LENGTH];\n");
                        cgc.WriteOutput("\nextern const int " + enumlistname + "_c_int_list[" + enumlistname.toUpperCase() + "_C_LENGTH];\n");
                        if (null != c_format_function_name) {
                            cgc.WriteOutput("\nextern const char *" + c_format_function_name.substring(0, c_format_function_name.length() - 6) + enumlistname + "_symbol_lookup(long v);\n");
                        }
                        cgc.WriteOutput("\nextern const struct cms_enum_info " + enumlistname + "_c_info_struct;\n");
                    }
                }
                cgc.WriteOutput("\n");
            } catch (Exception e) {
                e.printStackTrace();
            }

            if (!CodeGenCommon.no_format) {
                cgc.WriteOutput("extern int " + c_format_function_name + "(long type, void *buffer, struct cms_c_struct *cms);\n");
            }

            if (!CodeGenCommon.no_swig) {
                cgc.WriteOutput("extern long nml_" + swig_module_name + "_open(const char *buf, const char *proc, const char *cfg);\n");
                cgc.WriteOutput("extern void nml_" + swig_module_name + "_close(long nml_id);\n");
                cgc.WriteOutput("extern int  nml_" + swig_module_name + "_read(long nml_id);\n");
                cgc.WriteOutput("extern int  nml_" + swig_module_name + "_valid(long nml_id);\n");


                for (int i = 0; i < selected_classes.length; i++) {
                    type_info = (StructureTypeInfo) ModuleInfo.m_structInfoByNameHashTable.get(selected_classes[i]);
                    if (type_info != null && type_info.Id > 0) {
                        cgc.WriteOutput("\n");
                        cgc.WriteOutput("extern int nml_" + swig_module_name + "_" + type_info.Name + "_write(long nml_id, " + "const nml_" + type_info.Name + "_c_t *msg);\n");
                        cgc.WriteOutput("extern nml_" + type_info.Name + "_c_t * nml_" + swig_module_name + "_" + type_info.Name + "_get_msg(long nml_id);\n");
                    }
                }

                cgc.WriteOutput("\n");
            }

            cgc.WriteOutput("#ifndef SWIG\n");
            cgc.WriteOutput("#ifdef __cplusplus\n");
            cgc.WriteOutput("}\n");
            cgc.WriteOutput("#endif\n");
            cgc.WriteOutput("#endif\n");
            cgc.WriteOutput("\n");

            cgc.WriteOutput("#endif\n\t/* # endif " + currentOutputFileName.replace('.', '_') + "_included */ \n");
            cgc.WriteOutput("\n");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    static public String LastC_StartOfFile_Generated = null;

    static public void GenerateC_StartOfFile(String selected_classes[],
            CodeGenCommonInterface2 cgc,
            String currentOutputFileName,
            java.util.Hashtable enumInfoHashTable,
            String c_prototypes_header_string) {
        try {
            if (null != LastC_StartOfFile_Generated && null != currentOutputFileName
                    && LastC_StartOfFile_Generated.equals(currentOutputFileName)) {
                return;
            }
            LastC_StartOfFile_Generated = currentOutputFileName;

            if (selected_classes.length < 1) {
                return;
            }
            StructureTypeInfo type_info = (StructureTypeInfo) ModuleInfo.m_structInfoByNameHashTable.get(selected_classes[0]);
            if (debug_on) {
                DebugPrint("type_info=" + type_info);
                DebugPrint("type_info.first_module_used_in=" + type_info.first_module_used_in);
            }

            cgc.WriteOutput("/*\n*\tNew C++ File starts here.\n*\tThis file should be named " + currentOutputFileName + "\n*/\n\n");
            cgc.WriteOutput("/* Include all C language NML and CMS function prototypes. */\n");
            cgc.WriteOutput("#include \"nmlcms_c.h\"\n\n");
            if (c_prototypes_header_string != null) {
                cgc.WriteOutput("/* Include externally supplied prototypes. */\n");
                cgc.WriteOutput("#include \"" + c_prototypes_header_string + "\"\n");
            }
            cgc.WriteOutput("\n");

            cgc.WriteOutput("/* Forward Function Prototypes */\n");
            cgc.WriteOutput("#ifdef __cplusplus\n");
            cgc.WriteOutput("extern \"C\" {\n");
            cgc.WriteOutput("#endif\n");
            cgc.WriteOutput("\n");

            WriteC_UpdateFunctionProtos(selected_classes, cgc);

            cgc.WriteOutput("\n");
            cgc.WriteOutput("#ifdef __cplusplus\n");
            cgc.WriteOutput("}\n");
            cgc.WriteOutput("#endif\n");

            if (!CodeGenCommon.no_swig) {
                String c_format_function_name = Get_C_FormatFunction(selected_classes, cgc);
                String swig_module_name = c_format_function_name.substring(0, c_format_function_name.length() - 9);

                cgc.WriteOutput("long nml_" + swig_module_name + "_open(const char *buf, const char *proc, const char *cfg)\n");

                cgc.WriteOutput("{\n");
                cgc.WriteOutput("\treturn (long) nml_new(" + c_format_function_name + ", buf,proc,cfg);\n");
                cgc.WriteOutput("}\n");
                cgc.WriteOutput("\n");

                cgc.WriteOutput("int  nml_" + swig_module_name + "_valid(long nml_id)\n");
                cgc.WriteOutput("{\n");
                cgc.WriteOutput("\treturn (int) nml_valid( (nml_c_t) nml_id);\n");
                cgc.WriteOutput("}\n");
                cgc.WriteOutput("\n");

                cgc.WriteOutput("void nml_" + swig_module_name + "_close(long nml_id)\n");
                cgc.WriteOutput("{\n");
                cgc.WriteOutput("\tnml_free( (nml_c_t) nml_id);\n");
                cgc.WriteOutput("}\n");
                cgc.WriteOutput("\n");

                cgc.WriteOutput("int nml_" + swig_module_name + "_read(long nml_id)\n");
                cgc.WriteOutput("{\n");
                cgc.WriteOutput("\treturn (long) nml_read( (nml_c_t) nml_id);\n");
                cgc.WriteOutput("}\n");
                cgc.WriteOutput("\n");

                for (int i = 0; i < selected_classes.length; i++) {
                    type_info = (StructureTypeInfo) ModuleInfo.m_structInfoByNameHashTable.get(selected_classes[i]);
                    if (type_info != null && type_info.Id > 0) {
                        cgc.WriteOutput("int nml_" + swig_module_name + "_" + type_info.Name + "_write(long nml_id, " + "const nml_" + type_info.Name + "_c_t *msg)");
                        cgc.WriteOutput("{\n");
                        cgc.WriteOutput("\treturn (int) nml_write( (nml_c_t) nml_id,(void *) msg, (nmltype_c_t) " + type_info.Id + ",sizeof(nml_" + type_info.Name + "_c_t));\n");
                        cgc.WriteOutput("}\n");
                        cgc.WriteOutput("\n");

                        cgc.WriteOutput("nml_" + type_info.Name + "_c_t * nml_" + swig_module_name + "_" + type_info.Name + "_get_msg(long nml_id)");
                        cgc.WriteOutput("{\n");
                        cgc.WriteOutput("\treturn (nml_" + type_info.Name + "_c_t *) nml_get_address( (nml_c_t) nml_id);\n");
                        cgc.WriteOutput("}\n");
                        cgc.WriteOutput("\n");

                    }
                }

                cgc.WriteOutput("\n");
            }

            cgc.WriteOutput("\n");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // @SuppressWarnings("unchecked")
    static public void GenerateC_FormatFunction(String selected_classes[],
            CodeGenCommonInterface2 cgc,
            String currentOutputFileName,
            Hashtable enumInfoHashTable,
            String c_prototypes_header_string,
            boolean no_array_indexes) {
        StructureTypeInfo type_info = null;
        try {
            if (debug_on) {
                DebugPrint("GenerateC_FormatFunction");
            }
            GenerateC_StartOfFile(selected_classes, cgc, currentOutputFileName, enumInfoHashTable, c_prototypes_header_string);

            if (selected_classes.length < 1) {
                return;
            }
            if (null != m_loadingPanel && display_on) {
                m_loadingPanel.set_URLname("Generating C Format Function . . . ");
                m_loadingPanel.set_bytes_read(0);
                m_loadingPanel.set_content_length(2 * selected_classes.length);
                m_loadingPanel.force_repaint(500);
            }
            String c_format_function_name = Get_C_FormatFunction(selected_classes, cgc);
            String symbol_lookup_function_name = null;
            String namelist_name = null;
            String idlist_name = null;
            String sizelist_name = null;
            if (null != c_format_function_name) {
                if (!c_format_function_name.toUpperCase().endsWith("FORMAT")) {
                    symbol_lookup_function_name = c_format_function_name;
                } else {
                    symbol_lookup_function_name = c_format_function_name.substring(0, c_format_function_name.length() - 6);
                }
                if (symbol_lookup_function_name.endsWith("_")) {
                    symbol_lookup_function_name += "symbol_lookup";
                } else {
                    symbol_lookup_function_name += "_symbol_lookup";
                }

                idlist_name = c_format_function_name.substring(0, c_format_function_name.length() - 6);
                idlist_name += "id_list";
                sizelist_name = c_format_function_name.substring(0, c_format_function_name.length() - 6);
                sizelist_name += "size_list";
                namelist_name = c_format_function_name.substring(0, c_format_function_name.length() - 6);
                namelist_name += "name_list";
            }
            cgc.WriteOutput("\n");
            int longest_name_length = 0;
            int number_of_names = 0;
            for (int i = 0; i < selected_classes.length; i++) {
                type_info = (StructureTypeInfo) ModuleInfo.m_structInfoByNameHashTable.get(selected_classes[i]);
                if (null == type_info) {
                    continue;
                }
                if (type_info.Id <= 0 || type_info.DerivedFrom == null) {
                    continue;
                }
                number_of_names++;
                if (selected_classes[i].length() > longest_name_length) {
                    longest_name_length = selected_classes[i].length();
                }
            }
            if (null != namelist_name && null != sizelist_name && null != idlist_name && null != symbol_lookup_function_name) {
                cgc.WriteOutput("#ifndef MAX_" + namelist_name.substring(0, namelist_name.length() - 5).toUpperCase() + "_LENGTH\n");
                cgc.WriteOutput("#define MAX_" + namelist_name.substring(0, namelist_name.length() - 5).toUpperCase() + "_LENGTH " + (longest_name_length + 1) + "\n");
                cgc.WriteOutput("#endif\n");
                cgc.WriteOutput("#ifndef " + namelist_name.toUpperCase() + "_LENGTH\n");
                cgc.WriteOutput("#define " + namelist_name.toUpperCase() + "_LENGTH " + (number_of_names + 1) + "\n");
                cgc.WriteOutput("#endif\n");
                cgc.WriteOutput("\n");
                cgc.WriteOutput("\n/* This list must be in alphabetical order and the three lists must correspond. */\n");
                cgc.WriteOutput("const char " + namelist_name + "[" + namelist_name.toUpperCase() + "_LENGTH][MAX_" + namelist_name.substring(0, namelist_name.length() - 5).toUpperCase() + "_LENGTH]= {\n");
                for (int i = 0; i < selected_classes.length; i++) {
                    type_info = (StructureTypeInfo) ModuleInfo.m_structInfoByNameHashTable.get(selected_classes[i]);
                    if (null == type_info) {
                        continue;
                    }
                    if (type_info.Id <= 0 || type_info.DerivedFrom == null) {
                        continue;
                    }
                    cgc.WriteOutput("\t\"" + selected_classes[i] + "\", /* " + i + "," + type_info.Id + " */\n");
                }
                cgc.WriteOutput("\t\"\"};\n");
                cgc.WriteOutput("const NMLTYPE " + idlist_name + "[" + namelist_name.toUpperCase() + "_LENGTH]= {\n");
                for (int i = 0; i < selected_classes.length; i++) {
                    type_info = (StructureTypeInfo) ModuleInfo.m_structInfoByNameHashTable.get(selected_classes[i]);
                    if (null == type_info) {
                        continue;
                    }
                    if (type_info.Id <= 0 || type_info.DerivedFrom == null) {
                        continue;
                    }
                    cgc.WriteOutput("\t" + type_info.type_id_string + ", /* " + i + "," + type_info.Id + " */\n");
                }
                cgc.WriteOutput("\t-1};\n");
                cgc.WriteOutput("const size_t " + sizelist_name + "[" + namelist_name.toUpperCase() + "_LENGTH]= {\n");
                for (int i = 0; i < selected_classes.length; i++) {
                    type_info = (StructureTypeInfo) ModuleInfo.m_structInfoByNameHashTable.get(selected_classes[i]);
                    if (null == type_info) {
                        continue;
                    }
                    if (type_info.Id <= 0 || type_info.DerivedFrom == null) {
                        continue;
                    }
                    cgc.WriteOutput("\tsizeof(nml_" + selected_classes[i] + "_c_t),\n");
                }
                cgc.WriteOutput("\t0};\n");
                cgc.WriteOutput("const char *" + symbol_lookup_function_name + "(long type);\n");
                cgc.WriteOutput("\n");
            }
            try {
                if (null != enumInfoHashTable && !CodeGenCommon.no_enums) {
                    cgc.WriteOutput("\n/* Enumerated Type Constants */\n");
                    Enumeration enum_info_types = enumInfoHashTable.elements();
                    while (enum_info_types.hasMoreElements()) {
                        EnumTypeInfo enum_info = (EnumTypeInfo) enum_info_types.nextElement();
                        if (null == enum_info) {
                            continue;
                        }
                        if (null == enum_info.reverse_hashtable) {
                            continue;
                        }
                        if (enum_info.reverse_hashtable.size() < 1) {
                            continue;
                        }
                        cgc.WriteOutput("\n/*  " + enum_info.Name + " */\n");
                        int maxenumvalstringlength = 0;
                        int numenumvals = 0;

                        Enumeration enum_keys = enum_info.reverse_hashtable.keys();
                        Vector sorted_enum_key_vector = new Vector();
                        while (enum_keys.hasMoreElements()) {
                            String key = (String) enum_keys.nextElement();
                            numenumvals++;
                            if (maxenumvalstringlength < key.length()) {
                                maxenumvalstringlength = key.length();
                            }
                            boolean keyadded = false;
                            for (int ki = 0; ki < sorted_enum_key_vector.size(); ki++) {
                                String compareKey = (String) sorted_enum_key_vector.elementAt(ki);
                                if (key.compareTo(compareKey) < 0) {
                                    sorted_enum_key_vector.insertElementAt(key, ki);

                                    keyadded = true;
                                    break;
                                }
                            }
                            if (!keyadded) {
                                sorted_enum_key_vector.addElement(key);
                            }
                        }
                        String enumlistname =
                                /// c_format_function_name.substring(0,c_format_function_name.length()-6)+
                                "enum_" + enum_info.Name;
                        cgc.WriteOutput("#ifndef MAX_" + enumlistname.toUpperCase() + "_STRING_LENGTH\n");
                        cgc.WriteOutput("#define MAX_" + enumlistname.toUpperCase() + "_STRING_LENGTH "
                                + (maxenumvalstringlength + 1) + "\n");
                        cgc.WriteOutput("#endif\n");
                        cgc.WriteOutput("#ifndef " + enumlistname.toUpperCase() + "_LENGTH\n");
                        cgc.WriteOutput("#define " + enumlistname.toUpperCase() + "_LENGTH " + (numenumvals + 1) + "\n");
                        cgc.WriteOutput("#endif\n");

                        cgc.WriteOutput("\nconst char " + enumlistname + "_string_list[" + enumlistname.toUpperCase()
                                + "_LENGTH][MAX_" + enumlistname.toUpperCase() + "_STRING_LENGTH]= {\n");
                        int ski = 0;
                        for (ski = 0; ski < sorted_enum_key_vector.size(); ski++) {
                            String key = (String) sorted_enum_key_vector.elementAt(ski);
                            String ovn_keyname = key;
                            if (null != enum_info.override_names_hashtable) {
                                ovn_keyname = (String) enum_info.override_names_hashtable.get(key);
                                if (null == ovn_keyname) {
                                    ovn_keyname = key;
                                }
                            }
                            int val = -1;
                            try {
                                Integer Ival = (Integer) enum_info.reverse_hashtable.get(key);
                                val = Ival.intValue();
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                            if (!key.equals(ovn_keyname)) {
                                cgc.WriteOutput("\t\"" + ovn_keyname + "\", /* " + ski + "," + val + ",sym=" + key + " */\n");
                            } else {
                                cgc.WriteOutput("\t\"" + ovn_keyname + "\", /* " + ski + "," + val + " */\n");
                            }

                        }
                        cgc.WriteOutput("\t\"\"};\n");

                        cgc.WriteOutput("\nconst int " + enumlistname + "_int_list[" + enumlistname.toUpperCase()
                                + "_LENGTH]= {\n");
                        for (ski = 0; ski < sorted_enum_key_vector.size(); ski++) {
                            String key = (String) sorted_enum_key_vector.elementAt(ski);
                            String ovn_keyname = null;
                            if (null != enum_info.override_names_hashtable) {
                                ovn_keyname = (String) enum_info.override_names_hashtable.get(key);
                            }
                            int val = -1;
                            try {
                                Integer Ival = (Integer) enum_info.reverse_hashtable.get(key);
                                val = Ival.intValue();
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                            if (ovn_keyname != null) {
                                cgc.WriteOutput("\t" + key + "," + " /* " + ski + "," + val + ",name=" + ovn_keyname + " */\n");
                            } else {
                                cgc.WriteOutput("\t" + key + "," + " /* " + ski + "," + val + " */\n");
                            }
                        }
                        cgc.WriteOutput("\t};\n");
                        cgc.WriteOutput("\nconst char *" + c_format_function_name.substring(0, c_format_function_name.length() - 6) + enumlistname + "_symbol_lookup(long v)\n{\n\tswitch(v)\n\t{\n");
                        Vector vv = new Vector();
                        for (ski = 0; ski < sorted_enum_key_vector.size(); ski++) {
                            String key = (String) sorted_enum_key_vector.elementAt(ski);
                            String ovn_keyname = key;
                            if (null != enum_info.override_names_hashtable) {
                                ovn_keyname = (String) enum_info.override_names_hashtable.get(key);
                                if (null == ovn_keyname) {
                                    ovn_keyname = key;
                                }
                            }
                            Integer Ival = (Integer) enum_info.reverse_hashtable.get(key);
                            int ival = Ival.intValue();
                            boolean ival_found = false;
                            int vvi = 0;
                            for (vvi = 0; vvi < vv.size(); vvi++) {
                                Integer Ival2 = (Integer) vv.elementAt(vvi);
                                int ival2 = Ival2.intValue();
                                if (ival == ival2) {
                                    ival_found = true;
                                    break;
                                }
                            }
                            vv.addElement(Ival);
                            if (ival_found) {
                                String competingKey = (String) sorted_enum_key_vector.elementAt(vvi);
                                cgc.WriteOutput("\t\t/* " + key + " has the same value as " + competingKey + " of " + ival + " */\n");
                                continue;
                            }
                            cgc.WriteOutput("\t\tcase " + key + ':' + " return(\"" + ovn_keyname + "\"); /* " + ival + " */\n");
                        }
                        cgc.WriteOutput("\t\tdefault" + ':' + "break;\n\t}\n\treturn(NULL);\n}\n");
                        cgc.WriteOutput("\nconst struct cms_enum_info " + enumlistname + "_info_struct={\n");
                        cgc.WriteOutput("\t\"" + enum_info.Name + "\",\n\t(const char **)" + enumlistname + "_string_list,\n");
                        cgc.WriteOutput("\t" + enumlistname + "_int_list,\n\tMAX_" + enumlistname.toUpperCase() + "_STRING_LENGTH,\n");
                        cgc.WriteOutput("\t" + enumlistname.toUpperCase() + "_LENGTH,\n");
                        cgc.WriteOutput("\t(cms_symbol_lookup_function_t)" + c_format_function_name.substring(0, c_format_function_name.length() - 6) + enumlistname + "_symbol_lookup\n\t};\n");
                    }
                }
                cgc.WriteOutput("\n");
            } catch (Exception e) {
                e.printStackTrace();
            }

            cgc.WriteOutput("/*\n*\tNML/CMS Format function : " + c_format_function_name + "\n");
            cgc.WriteOutput("*\tAutomatically generated by NML CodeGen Java Applet.\n");
            cgc.WriteOutput("*/\n");

            cgc.WriteOutput("int " + c_format_function_name + "(long type, void *buffer, struct cms_c_struct *cms)\n{\n");
            cgc.WriteOutput("\n");
            if (no_array_indexes) {
                cgc.WriteOutput("\tcms_set_add_array_indexes_to_name(0);\n");
            }
            cgc.WriteOutput("\ttype = cms_check_type_info(cms,type,buffer,\"" + c_format_function_name.substring(0, c_format_function_name.length() - 7) + "\",\n"
                    + "\t\t(cms_symbol_lookup_function_t) " + symbol_lookup_function_name + ",\n"
                    + "\t\t(const char **)" + namelist_name + ",\n\t\t" + idlist_name + "," + sizelist_name + ",\n"
                    + "\t\t" + namelist_name.toUpperCase() + "_LENGTH,\n"
                    + "\t\t" + "MAX_" + namelist_name.substring(0, namelist_name.length() - 5).toUpperCase() + "_LENGTH);\n");
            cgc.WriteOutput("\n");
            cgc.WriteOutput("\tswitch(type)\n\t{\n");

            for (int i = 0; i < selected_classes.length; i++) {
                type_info = (StructureTypeInfo) ModuleInfo.m_structInfoByNameHashTable.get(selected_classes[i]);
                if (null != m_loadingPanel && display_on) {
                    m_loadingPanel.set_bytes_read(m_loadingPanel.get_bytes_read() + 1);
                    m_loadingPanel.force_repaint(500);
                }
                if (null == type_info) {
                    continue;
                }
                if (type_info.Id <= 0 || type_info.DerivedFrom == null) {
                    continue;
                }
                cgc.WriteOutput("\tcase " + type_info.type_id_string + ":\n\t\tcms_" + selected_classes[i] + "_update(cms,(nml_" + selected_classes[i] + "_c_t *) buffer);\n\t\tbreak;\n");
            }
            cgc.WriteOutput("\n\tdefault" + ':' + "\n\t\treturn(0);\n");
            cgc.WriteOutput("\t}\n\treturn 1;\n}\n");


            if (null != symbol_lookup_function_name) {
                cgc.WriteOutput("\n\n/* NML Symbol Lookup Function */\n");
                cgc.WriteOutput("const char *" + symbol_lookup_function_name + "(long type)\n{\n");
                cgc.WriteOutput("\tswitch(type)\n\t{\n");
                for (int i = 0; i < selected_classes.length; i++) {
                    type_info = (StructureTypeInfo) ModuleInfo.m_structInfoByNameHashTable.get(selected_classes[i]);
                    if (null != m_loadingPanel && display_on) {
                        m_loadingPanel.set_bytes_read(m_loadingPanel.get_bytes_read() + 1);
                        m_loadingPanel.force_repaint(500);
                    }
                    if (null == type_info) {
                        continue;
                    }
                    if (type_info.Id <= 0) {
                        continue;
                    }
                    cgc.WriteOutput("\tcase " + type_info.type_id_string + ":\n\t\treturn \"" + selected_classes[i] + "\";\n");

                }
                cgc.WriteOutput("\tdefault" + ':' + "\n\t\treturn\"UNKNOWN\";\n\t\tbreak;\n");
                cgc.WriteOutput("\t}\n\treturn(NULL);\n}\n");
            }
            c_format_function_name = null;
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("type_info=" + type_info);
        }
    }

    public static String ConvertCppTypeTo_C_Update_Suffix(String cpp_type) {
        String c_type = "int";
        try {
            StringTokenizer st = new StringTokenizer(cpp_type, " \t");
            String tok1 = "";
            String tok2 = "";
            String tok3 = "";
            if (st.hasMoreTokens()) {
                tok1 = st.nextToken();
            }
            if (st.hasMoreTokens()) {
                tok2 = st.nextToken();
            }
            if (st.hasMoreTokens()) {
                tok3 = st.nextToken();
            }
            if (tok1.equals("unsigned")) {
                if (tok2.length() < 1) {
                    return ("unsigned_int");
                } else if (tok2.equals("long") && tok3.equals("long")) {
                    return ("unsigned_long_long");
                } else if (tok2.equals("long")) {
                    return ("unsigned_long");
                } else {
                    return "unsigned_" + tok2;
                }
            } else if (tok1.equals("long") && tok2.equals("long")) {
                return ("long_long");
            } else {
                return tok1;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return c_type;

    }

    public static void CreateC_UpdateFunction(StructureTypeInfo type_info, CodeGenCommonInterface2 cgc, Hashtable enumInfoHashTable,
            ModuleInfo currentModule) {
        String info_token = null;
        int r_squareParamIndex = -1;
        int l_squareParamIndex = -1;
        int lastSpaceIndex = -1;
        String array_length_string = null;
        String variable_name = null;
        String cpp_type = null;
        int num_dims = 0;
        type_info.C_UpdateFunction = "";
        String orig_info_token = null;
        //	String trimmed_orig_info_token=null;
        int array_length = 1;
        boolean is_class = false;
        boolean is_enum = false;
        boolean is_posemath_class = false;
        boolean var_class_is_nml_msg = false;
        //	String union_selector_var_name = null;
        String stringToAdd = "";

        if (debug_on) {
            DebugPrint("CreateC_UpdateFunction: type_info.Name = " + type_info.Name);
            DebugPrint("CreateC_UpdateFunction: type_info.RawInfo = " + type_info.RawInfo);
            DebugPrint("CreateC_UpdateFunction: type_info.HiddenInfo = " + type_info.HiddenInfo);
            DebugPrint("CreateC_UpdateFunction: type_info.PreFinalPassInfo = " + type_info.PreFinalPassInfo);
        }

        try {
            StringTokenizer info_tokenizer = new StringTokenizer(type_info.PreFinalPassInfo, ";");
            //DebugPrint("Creating Update Function for "+type_info.Name);

            // If this class was derived from another just eat the members of the base class.
            //		EnumTypeInfo union_enum_info=null;
            if (!type_info.is_union) {
                if (null != type_info.DerivedFrom) {
                    stringToAdd =
                            "\n\tcms_begin_class(cms,\"" + type_info.Name + "\",\"" + type_info.UnqualifiedDerivedFrom + "\");\n";
                    if (debug_on) {
                        DebugPrint("stringToAdd=" + stringToAdd);
                    }
                    type_info.C_UpdateFunction += stringToAdd;
                } else {
                    stringToAdd =
                            "\n\tcms_begin_class(cms,\"" + type_info.Name + "\",0);\n";
                    if (debug_on) {
                        DebugPrint("stringToAdd=" + stringToAdd);
                    }
                    type_info.C_UpdateFunction += stringToAdd;
                }
            } else {
                System.err.println("unions not supported for NML C interface");
                type_info.C_UpdateFunction = "\n#error unions not supported for NML C interface\n";
                return;
                /* 
                String union_enum_name= StringFuncs.replaceFirstInString(type_info.Name,"Union","_UNION_ENUM");
                union_enum_info = (EnumTypeInfo)   ModuleInfo.m_enumInfoHashTable.get(union_enum_name);
                if(union_enum_info == null)
                {
                System.err.println("Bad union definition "+type_info.Name+", no corresponding enum "+union_enum_name);
                return;
                }
                type_info.C_UpdateFunction += 
                "\n\tcms->beginUnion(\""+type_info.Name + "\");\n";
                type_info.C_UpdateFunction += 
                "\n\tswitch(union_selector)\n\t{\n";
                 */
            }
            if (null != type_info.DerivedFrom) {
                if (debug_on) {
                    DebugPrint("CreateC_UpdateFunction: type_info.DerivedFrom = " + type_info.DerivedFrom);
                }
                if (!type_info.DerivedFrom.equals("RCS_CMD_MSG")
                        && !type_info.DerivedFrom.equals("RCS_STAT_MSG")
                        && !type_info.DerivedFrom.equals("NMLmsg")) {
                    stringToAdd =
                            "\n\tcms_begin_base_class(cms,\"" + type_info.UnqualifiedDerivedFrom + "\");";
                    is_posemath_class = cgc.CheckForCppPosemathClass(type_info.DerivedFrom);
                    if (is_posemath_class) {
                        System.err.println("Can not use Posemath Classes with NML C interface.\n");
                        type_info.C_UpdateFunction = "\n#error Can not use Posemath Classes with NML C interface.\n";
                        return;
                        /*
                        if(debug_on)
                        {
                        DebugPrint("CreateC_UpdateFunction: is_posemath_class = "+is_posemath_class);
                        }
                        type_info.C_UpdateFunction  +=  "\n\tcms->update(* (("+type_info.DerivedFrom+") x);\n";
                         */
                    } else {
                        var_class_is_nml_msg = cgc.IsNMLMsg(type_info.DerivedFrom);
                        if (debug_on) {
                            DebugPrint("CreateC_UpdateFunction: var_class_is_nml_msg = " + var_class_is_nml_msg);
                        }
                        if (var_class_is_nml_msg != type_info.is_nml_msg) {
                            String tmperrstring = type_info.Name + " appears to be derived from " + type_info.DerivedFrom + " but IsNMLMsg(\"" + type_info.DerivedFrom + "\") returned " + var_class_is_nml_msg + " and type_info.is_nml_msg = " + type_info.is_nml_msg;
                            System.err.println(tmperrstring);
                            type_info.C_UpdateFunction = "\n#error " + tmperrstring + "\n";
                            return;
                        }
                        StructureTypeInfo derived_from_type_info = (StructureTypeInfo) ModuleInfo.m_structInfoByNameHashTable.get(type_info.DerivedFrom);
                        if (null != derived_from_type_info) {
                            if (null == derived_from_type_info.C_UpdateFunction) {
                                CreateC_UpdateFunction(derived_from_type_info, cgc, enumInfoHashTable, currentModule);
                            }
                            if (null != derived_from_type_info.C_UpdateFunction) {
                                stringToAdd = "";
                                stringToAdd += "\n{\n";
                                stringToAdd += derived_from_type_info.C_UpdateFunction;
                                stringToAdd += "\n}\n";
                                if (debug_on) {
                                    DebugPrint("stringToAdd=" + stringToAdd);
                                }
                                type_info.C_UpdateFunction += stringToAdd;
                            }
                        }
                    }
                    stringToAdd =
                            "\tcms_end_base_class(cms,\"" + type_info.UnqualifiedDerivedFrom + "\");\n\n";
                    if (debug_on) {
                        DebugPrint("stringToAdd=" + stringToAdd);
                    }
                    type_info.C_UpdateFunction += stringToAdd;
                } else if (type_info.DerivedFrom.equals("RCS_CMD_MSG")) {
                    stringToAdd = "";
                    stringToAdd +=
                            "\tcms_begin_update_cmd_msg_base(cms,(void*)x);\n";
                    stringToAdd +=
                            "\tcms_update_int(cms,\"serial_number\",&(x->serial_number));";
                    stringToAdd +=
                            "\tcms_end_update_cmd_msg_base(cms,(void*)x);\n";
                    if (debug_on) {
                        DebugPrint("stringToAdd=" + stringToAdd);
                    }
                    type_info.C_UpdateFunction += stringToAdd;
                } else if (type_info.DerivedFrom.equals("RCS_STAT_MSG")) {
                    stringToAdd = "";
                    stringToAdd +=
                            "\tcms_begin_update_stat_msg_base(cms,(void*)x);\n";
                    stringToAdd +=
                            "\tcms_update_long(cms,\"command_type\",&(x->command_type));\n";
                    stringToAdd +=
                            "\tcms_update_int(cms,\"echo_serial_number\",&(x->echo_serial_number));\n";
                    stringToAdd +=
                            "\tx->status= (enum RCS_STATUS) cms_update_enumeration(cms,\"status\", (int)x->status,(void*)&(x->status),&enum_RCS_STATUS_info_struct);\n";
                    stringToAdd +=
                            "\tcms_update_int(cms,\"status\",&(x->status));\n";
                    stringToAdd +=
                            "\tcms_update_int(cms,\"state\",&(x->state));\n";
                    stringToAdd +=
                            "\tcms_update_int(cms,\"source_line\",&(x->source_line));\n";
                    stringToAdd +=
                            "\tcms_update_char_array(cms,\"source_file\",(x->source_file),64);\n";
                    stringToAdd +=
                            "\tcms_end_update_stat_msg_base(cms,(void*)x);\n";
                    if (debug_on) {
                        DebugPrint("stringToAdd=" + stringToAdd);
                    }
                    type_info.C_UpdateFunction += stringToAdd;
                }
            }
            boolean dynamic_array = false;
            boolean unbounded_array = false;
            String ndla_string = CodeGenCommonInterface.ndla_string;
            String unbounded_string = CodeGenCommonInterface.unbounded_string;
            while (info_tokenizer.hasMoreTokens()) {
                info_token = info_tokenizer.nextToken();
                int nml_dynamic_length_array_index = info_token.indexOf(ndla_string);
                if (nml_dynamic_length_array_index >= 0) {
                    info_token = info_token.substring(nml_dynamic_length_array_index + ndla_string.length());
                    dynamic_array = true;
                } else {
                    dynamic_array = false;
                }
                int nml_unbounded_length_array_index = info_token.indexOf(unbounded_string);
                if (nml_unbounded_length_array_index >= 0) {
                    info_token = info_token.substring(nml_unbounded_length_array_index + unbounded_string.length());
                    unbounded_array = true;
                } else {
                    unbounded_array = false;
                }
                orig_info_token = info_token;
                info_token = info_token.trim();
                //trimmed_orig_info_token=info_token;
                //DebugPrint("info_token = "+info_token);
                array_length_string = null;
                variable_name = null;
                cpp_type = null;
                num_dims = 0;
                while (true) {
                    if (info_token.charAt(0) != ' '
                            && info_token.charAt(0) != '\t'
                            && info_token.charAt(0) != '\r'
                            && info_token.charAt(0) != '\n') {
                        break;
                    }
                    if (info_token.length() < 2) {
                        break;
                    }
                    info_token = info_token.substring(1);
                }
                if (info_token.length() < 2) {
                    continue;
                }
                l_squareParamIndex = info_token.indexOf('[');
                String pre_array_string = info_token;
                if (l_squareParamIndex > 0) {
                    r_squareParamIndex = info_token.indexOf(']', l_squareParamIndex);
                    pre_array_string = info_token.substring(0, l_squareParamIndex);
                }
                array_length = 1;
                while (-1 != r_squareParamIndex && -1 != l_squareParamIndex) {
                    array_length_string = info_token.substring(l_squareParamIndex + 1, r_squareParamIndex);
                    array_length_string = currentModule.ReplaceDefinedValues(array_length_string, 0, null);
                    int this_dim_length = ModuleInfo.doArrayLengthMath(array_length_string);
                    array_length *= this_dim_length;
                    num_dims++;
                    if (debug_on) {
                        DebugPrint("this_dim_length = " + this_dim_length + ", array_length = " + array_length + ", info_token = " + info_token);
                    }
                    l_squareParamIndex = info_token.indexOf('[', l_squareParamIndex + 1);
                    r_squareParamIndex = info_token.indexOf(']', l_squareParamIndex + 1);
                }
                while (true) {
                    if (pre_array_string.length() < 2) {
                        break;
                    }
                    char last_char = pre_array_string.charAt(pre_array_string.length() - 1);
                    if (last_char != ' '
                            && last_char != '\t'
                            && last_char != '\r'
                            && last_char != '\n') {
                        break;
                    }
                    pre_array_string = pre_array_string.substring(pre_array_string.length() - 1);
                }
                lastSpaceIndex = pre_array_string.lastIndexOf(' ');
                if (lastSpaceIndex < 0) {
                    System.err.println("Invalid variable definition (" + orig_info_token + ") in class " + type_info.Name);
                    System.err.println("\t\t-- pre_array_string (" + pre_array_string + ") needs a space. *2");
                    cgc.RingBell();
                    continue;
                }


                variable_name = pre_array_string.substring(lastSpaceIndex + 1);
                l_squareParamIndex = variable_name.indexOf('[');
                if (l_squareParamIndex > 0) {
                    variable_name = variable_name.substring(0, l_squareParamIndex);
                }
                if (variable_name.length() < 1) {
                    lastSpaceIndex = info_token.lastIndexOf(' ', lastSpaceIndex - 1);
                    if (lastSpaceIndex < 0) {
                        System.err.println("Invalid variable definition (" + orig_info_token + ") in class " + type_info.Name);
                        System.err.println("\t\t-- info_token (" + info_token + ") needs another space. L2313--28%");
                        cgc.RingBell();
                        continue;
                    }
                    variable_name = info_token.substring(lastSpaceIndex + 1);
                    l_squareParamIndex = variable_name.indexOf('[');
                    if (l_squareParamIndex > 0) {
                        variable_name = variable_name.substring(0, l_squareParamIndex);
                    }
                }
                if (variable_name.length() < 1) {
                    System.err.println("Invalid variable definition (" + orig_info_token + ") in class " + type_info.Name);
                    System.err.println("\t\t-- no variable_name.");
                    cgc.RingBell();
                    continue;
                }
                if (variable_name.indexOf('*') >= 0 || variable_name.indexOf('&') >= 0) {
                    System.err.println("Invalid variable definition (" + orig_info_token + ") in class " + type_info.Name);
                    System.err.println("\t\t-- variable (" + variable_name + ") appears to be a pointer or reference.");
                    stringToAdd = "\n#error Can not create update for pointer or reference type (" + orig_info_token + ")\n";
                    if (debug_on) {
                        DebugPrint("stringToAdd=" + stringToAdd);
                    }
                    type_info.C_UpdateFunction += stringToAdd;
                    cgc.RingBell();
                    continue;
                }
                if (variable_name.indexOf('*') >= 0
                        || variable_name.indexOf(' ') >= 0
                        || variable_name.indexOf('?') >= 0
                        || variable_name.indexOf('-') >= 0
                        || variable_name.indexOf('\\') >= 0
                        || variable_name.indexOf('/') >= 0
                        || variable_name.indexOf('+') >= 0
                        || variable_name.indexOf('=') >= 0
                        || variable_name.indexOf('+') >= 0
                        || variable_name.indexOf('<') >= 0 || variable_name.indexOf('>') >= 0
                        || variable_name.indexOf('[') >= 0 || variable_name.indexOf(']') >= 0
                        || variable_name.indexOf('(') >= 0 || variable_name.indexOf(')') >= 0
                        || variable_name.indexOf('{') >= 0 || variable_name.indexOf('}') >= 0
                        || variable_name.indexOf(',') >= 0
                        || variable_name.indexOf('&') >= 0) {
                    System.err.println("Invalid variable definition (" + orig_info_token + ") in class " + type_info.Name);
                    System.err.println("\t\t-- variable_name (" + variable_name + ") contains an illegal character.");
                    cgc.RingBell();
                    continue;
                }
                String ovn_variable_name = variable_name;
                String override_name = (String) type_info.VarnameOverridesHashTable.get(variable_name);
                if (override_name != null) {
                    ovn_variable_name = override_name;
                    if (debug_on) {
                        DebugPrint("CreateC_Update : variable_name=" + variable_name + ", override_name=" + override_name);
                    }
                }
                String att_add = "";
                cpp_type = info_token.substring(0, lastSpaceIndex);
                if (type_info.VarnameAttributeInfoHashTable.containsKey(variable_name)) {
                    att_add = "_attribute";
                } else if (variable_name.endsWith("_length")
                        && variable_name.length() > 7
                        && (type_info.VarnameNDLAHashTable.containsKey(variable_name.substring(0, variable_name.length() - 7))
                        || type_info.VarnameNDLAHashTable.containsKey(variable_name))) {
                    att_add = "_dla_length";
                }
                while (true) {
                    if (cpp_type.charAt(0) != ' '
                            && cpp_type.charAt(0) != '\t'
                            && cpp_type.charAt(0) != '\r'
                            && cpp_type.charAt(0) != '\n') {
                        break;
                    }
                    if (cpp_type.length() < 2) {
                        break;
                    }
                    cpp_type = cpp_type.substring(1);
                }
                int cpp_type_length = cpp_type.length();
                while (true) {
                    if (cpp_type.charAt(cpp_type_length - 1) != ' '
                            && cpp_type.charAt(cpp_type_length - 1) != '\t'
                            && cpp_type.charAt(cpp_type_length - 1) != '\r'
                            && cpp_type.charAt(cpp_type_length - 1) != '\n') {
                        break;
                    }
                    if (cpp_type.length() < 2) {
                        break;
                    }
                    cpp_type = cpp_type.substring(0, cpp_type_length - 1);
                    cpp_type_length = cpp_type.length();
                }
                if (cpp_type.indexOf('*') >= 0
                        || cpp_type.indexOf('&') >= 0) {
                    System.err.println("Invalid variable definition (" + orig_info_token + ") in class " + type_info.Name);
                    System.err.println("\t\t-- cpp_type (" + cpp_type + ") appears to be a pointer or reference.");
                    stringToAdd = "\n#error Can not create update for pointer or reference type (" + cpp_type + ")\n";
                    if (debug_on) {
                        DebugPrint("stringToAdd=" + stringToAdd);
                    }
                    type_info.C_UpdateFunction += stringToAdd;
                    cgc.RingBell();
                    continue;
                }
                if (cpp_type.indexOf('*') >= 0
                        || cpp_type.indexOf('?') >= 0
                        || cpp_type.indexOf('-') >= 0
                        || cpp_type.indexOf('\\') >= 0
                        || cpp_type.indexOf('/') >= 0
                        || cpp_type.indexOf('+') >= 0
                        || cpp_type.indexOf('=') >= 0
                        || cpp_type.indexOf('+') >= 0
                        || cpp_type.indexOf('<') >= 0 || cpp_type.indexOf('>') >= 0
                        || cpp_type.indexOf('[') >= 0 || cpp_type.indexOf(']') >= 0
                        || cpp_type.indexOf('(') >= 0 || cpp_type.indexOf(')') >= 0
                        || cpp_type.indexOf('{') >= 0 || cpp_type.indexOf('}') >= 0
                        || cpp_type.indexOf(',') >= 0
                        || cpp_type.indexOf('&') >= 0) {
                    System.err.println("Invalid variable definition (" + orig_info_token + ") in class " + type_info.Name);
                    System.err.println("\t\t-- cpp_type (" + cpp_type + ") contains an illegal character.");

                    continue;
                }
                is_class = cgc.CheckForCppClass(cpp_type);
                is_posemath_class = false;
                if (is_class) {
                    is_posemath_class = cgc.CheckForCppPosemathClass(cpp_type);
                    is_enum = false;
                } else {
                    is_enum = cgc.CheckForCppEnum(cpp_type);
                }
                if (debug_on) {
                    DebugPrint("info_token=" + info_token + ", unbouded_array=" + unbounded_array + ",dynamic_array=" + dynamic_array + ",is_class=" + is_class + ",is_enum=" + is_enum + ",array_length=" + array_length + ",variable_name=" + variable_name);
                }
                if (type_info.is_union) {
                    System.err.println("unions not supported for NML C interface");
                    type_info.C_UpdateFunction = "\n#error unions not supported for NML C interface\n";
                    return;
                    /* 
                    if(!union_enum_info.reverse_hashtable.containsKey("UNION_"+StringFuncs.replaceAllInString(type_info.Name,"Union","")+"_SELECTED_"+variable_name))
                    {
                    continue;
                    }
                    type_info.C_UpdateFunction += "\tcase UNION_"+StringFuncs.replaceAllInString(type_info.Name,"Union","")+"_SELECTED_"+variable_name+":\n\t";
                     */
                }
                if (!is_class && !is_posemath_class && !type_info.is_union) {
                    String defv = (String) type_info.VarnameToDefaultsHashTable.get(variable_name);
                    if (null != defv) {
                        stringToAdd = "\tcms_next_update_default(cms,\"" + defv + "\");\n";
                        if (debug_on) {
                            DebugPrint("stringToAdd=" + stringToAdd);
                        }
                        type_info.C_UpdateFunction += stringToAdd;
                    }
                }
                String c_update_suffix = ConvertCppTypeTo_C_Update_Suffix(cpp_type);

                if (array_length > 1) {
                    array_length_string = String.valueOf(array_length);
                    //DebugPrint("currentModule = "+currentModule);
                    //DebugPrint("variable_name = "+variable_name);
                    //DebugPrint(variable_name+"_ARRAY_LENGTH_VARIABLE");
                    if (null != currentModule) {
                        //DebugPrint("currentModule.definedValues ="+currentModule.definedValues);
                        if (null != currentModule.definedValues) {
                            DefinedValue dv = (DefinedValue) currentModule.definedValues.get(variable_name + "_ARRAY_LENGTH_VARIABLE");
                            //DebugPrint("dv ="+dv);
                            if (null != dv) {
                                array_length_string = dv.value;
                            }
                        }
                    }
                    String cast_string = "";
                    if (num_dims > 1) {
                        if (is_class) {
                            cast_string = "( nml_" + cpp_type + "_c_t *) ";
                        } else {
                            cast_string = "(" + cpp_type + " *) ";
                        }
                    }
                    if (is_class) {
                        if (!dynamic_array) {
                            stringToAdd = "";
                            stringToAdd += "\n\t{\n";
                            stringToAdd += "\t\tint i_" + variable_name + "=0;\n";
                            stringToAdd += "\n\t\tfor(i_" + variable_name + " = 0;i_" + variable_name + " < " + array_length_string + " ;i_" + variable_name + "++)\n";
                            stringToAdd += "\t\t{\n";
                            stringToAdd += "\t\t\tcms_begin_struct_array_elem(cms,\"" + ovn_variable_name + "\",i_" + variable_name + ");\n";
                            stringToAdd += "\t\t\tcms_" + StringFuncs.replace_white_space(cpp_type) + "_update(cms," + cast_string + "&((" + cast_string + " x->" + variable_name + ")[i_" + variable_name + "]));\n";
                            stringToAdd += "\t\t\tcms_end_struct_array_elem(cms,\"" + ovn_variable_name + "\",i_" + variable_name + ");\n";
                            stringToAdd += "\t\t}\n";
                            stringToAdd += "\t}\n\n";
                            if (debug_on) {
                                DebugPrint("stringToAdd=" + stringToAdd);
                            }
                            type_info.C_UpdateFunction += stringToAdd;
                        } else {
                            stringToAdd = "";
                            stringToAdd += "\tcms_begin_struct_dynamic_array(cms,\"" + ovn_variable_name + "\",&(x->" + variable_name + "_length), " + array_length_string + ");\n";
                            stringToAdd += "\n\t{\n";
                            stringToAdd += "\t\tint i_" + variable_name + "=0;\n";
                            stringToAdd += "\n\t\t\tfor(i_" + variable_name + " = 0;i_" + variable_name + " < x->" + variable_name + "_length; i_" + variable_name + "++)\n";
                            stringToAdd += "\t\t{\n";
                            stringToAdd += "\t\t\tcms_begin_struct_array_elem(cms,\"" + ovn_variable_name + "\",i_" + variable_name + ");\n";
                            stringToAdd += "\t\t\tcms_" + StringFuncs.replace_white_space(cpp_type) + "_update(cms," + cast_string + "&((" + cast_string + " x->" + variable_name + ")[i_" + variable_name + "]));\n";
                            stringToAdd += "\t\t\tcms_end_struct_array_elem(cms,\"" + ovn_variable_name + "\",i_" + variable_name + ");\n";
                            stringToAdd += "\t\t}\n";
                            stringToAdd += "\t}\n\n";
                            stringToAdd += "\tcms_end_struct_dynamic_array(cms,\"" + ovn_variable_name + "\",&(x->" + variable_name + "_length), " + array_length_string + ");\n";
                            if (debug_on) {
                                DebugPrint("stringToAdd=" + stringToAdd);
                            }
                            type_info.C_UpdateFunction += stringToAdd;
                        }
                    } else {
                        if (!dynamic_array) {
                            if (is_enum) {
                                String enum_name = cpp_type;
                                int lastspaceindex = cpp_type.lastIndexOf(' ');
                                if (lastspaceindex > 0) {
                                    enum_name = enum_name.substring(lastspaceindex + 1);
                                }
                                EnumTypeInfo enum_info =
                                        (EnumTypeInfo) ModuleInfo.m_enumInfoHashTable.get(enum_name);

                                stringToAdd = "";
                                stringToAdd += "\tcms_begin_enumeration_array(cms,\"" + ovn_variable_name + "\",&enum_" + enum_info.Name + "_info_struct," + array_length_string + ");\n";
                                stringToAdd += "\t{\n";
                                stringToAdd += "\t\tint i_" + variable_name + "=0;\n";
                                stringToAdd += "\t\tfor(i_" + variable_name + "=0; i_" + variable_name + " < " + array_length_string + "; i_" + variable_name + "++ )\n";
                                stringToAdd += "\t\t{\n";
                                if (!cpp_type.startsWith("enum ")) {
                                    stringToAdd += "\t\t\tx->" + variable_name + "[i_" + variable_name + "] = (enum " + cpp_type + ")\n";
                                } else {
                                    stringToAdd += "\t\t\tx->" + variable_name + "[i_" + variable_name + "] = (" + cpp_type + ")\n";
                                }
                                stringToAdd += "\t\t\t\tcms_update_enumeration_array_elem(cms,x->" + variable_name + "[i_" + variable_name + "],(int *) &(x->" + variable_name + "[i_" + variable_name + "]),i_" + variable_name + ");\n";
                                stringToAdd += "\t\t}\n";
                                stringToAdd += "\t}\n";
                                stringToAdd += "\tcms_end_enumeration_array(cms,\"" + ovn_variable_name + "\",&enum_" + enum_info.Name + "_info_struct," + array_length_string + ");\n";
                                if (debug_on) {
                                    DebugPrint("stringToAdd=" + stringToAdd);
                                }
                                type_info.C_UpdateFunction += stringToAdd;
                            } else {
                                stringToAdd = "\tcms_update" + att_add + "_" + c_update_suffix + "_array(cms,\"" + ovn_variable_name + "\"," + cast_string + "x->" + variable_name + "," + array_length_string + ");\n";
                                if (debug_on) {
                                    DebugPrint("stringToAdd=" + stringToAdd);
                                }
                                type_info.C_UpdateFunction += stringToAdd;
                            }
                        } else {
                            if (is_enum) {
                                String enum_name = cpp_type;
                                int lastspaceindex = cpp_type.lastIndexOf(' ');
                                if (lastspaceindex > 0) {
                                    enum_name = enum_name.substring(lastspaceindex + 1);
                                }
                                EnumTypeInfo enum_info =
                                        (EnumTypeInfo) ModuleInfo.m_enumInfoHashTable.get(enum_name);

                                stringToAdd = "";
                                stringToAdd += "\tcms_begin_enumeration_dla(cms,\"" + ovn_variable_name + "\",&enum_" + enum_info.Name + "_info_struct,&(x->" + variable_name + "_length)," + array_length_string + ");\n";
                                stringToAdd += "\t{\n";
                                stringToAdd += "\t\tint i_" + variable_name + "=0;\n";
                                stringToAdd += "\t\tfor(i_" + variable_name + "=0; i_" + variable_name + " < x->" + variable_name + "_length && x->" + variable_name + "_length <= " + array_length_string + "; i_" + variable_name + "++ )\n";
                                stringToAdd += "\t\t{\n";
                                if (!cpp_type.startsWith("enum ")) {
                                    stringToAdd += "\t\t\tx->" + variable_name + "[i_" + variable_name + "] = (enum " + cpp_type + ")\n";
                                } else {
                                    stringToAdd += "\t\t\tx->" + variable_name + "[i_" + variable_name + "] = (" + cpp_type + ")\n";
                                }
                                stringToAdd += "\t\t\t\tcms_update_enumeration_array_elem(cms,x->" + variable_name + "[i_" + variable_name + "],(int *) &(x->" + variable_name + "[i_" + variable_name + "]),i_" + variable_name + ");\n";
                                stringToAdd += "\t\t}\n";
                                stringToAdd += "\t}\n";
                                stringToAdd += "\tcms_end_enumeration_dla(cms,\"" + ovn_variable_name + "\",&enum_" + enum_info.Name + "_info_struct,&(x->" + variable_name + "_length)," + array_length_string + ");\n";
                                if (debug_on) {
                                    DebugPrint("stringToAdd=" + stringToAdd);
                                }
                                type_info.C_UpdateFunction += stringToAdd;
                            } else {
                                stringToAdd = "\tcms_update_" + c_update_suffix + "_dla(cms,\"" + ovn_variable_name + "\"," + cast_string + "x->" + variable_name + ", &(x->" + variable_name + "_length)," + array_length_string + ");\n";
                                if (debug_on) {
                                    DebugPrint("stringToAdd=" + stringToAdd);
                                }
                                type_info.C_UpdateFunction += stringToAdd;
                            }
                        }
                    }
                } else if (is_class) {
                    if (unbounded_array) {
                        stringToAdd = "";
                        stringToAdd += "\tcms_begin_struct_unbounded_array(cms,\"" + ovn_variable_name + "\",((void **) &(x->" + variable_name + ")), &(x->" + variable_name + "_length), &(x->" + variable_name + "_size_allocated),sizeof(" + cpp_type + "));\n";
                        stringToAdd += "\tif(0 != x->" + variable_name + ")\n\t{\n";
                        stringToAdd += "\t\tint i_" + variable_name + "=0;\n";
                        stringToAdd += "\t\tfor(i_" + variable_name + "=0; i_" + variable_name + " < x->" + variable_name + "_length && i_" + variable_name + " < x->" + variable_name + "_size_allocated ; i_" + variable_name + "++)\n\t\t{\n";
                        stringToAdd += "\t\t\tcms_begin_struct_array_elem(\"" + ovn_variable_name + "\", i_" + variable_name + ");\n";
                        stringToAdd += "\t\t\tcms_" + StringFuncs.replace_white_space(cpp_type) + "_update(cms, (" + cpp_type + " *) &((( n_" + cpp_type + "_c_t *) x->" + variable_name + ")[i_" + variable_name + "]));\n";
                        stringToAdd += "\t\t\tcms_end_struct_array_elem(cms,\"" + ovn_variable_name + "\", i_" + variable_name + ");\n";
                        stringToAdd += "\t\t}\n\t}\n";
                        stringToAdd += "\tcms_end_struct_unbounded_array(cms,\"" + ovn_variable_name + "\",((void **) &(x->" + variable_name + ")),&(x->" + variable_name + "_length), &(x->" + variable_name + "_size_allocated),sizeof(" + cpp_type + "));\n";
                        if (debug_on) {
                            DebugPrint("stringToAdd=" + stringToAdd);
                        }
                        type_info.C_UpdateFunction += stringToAdd;
                    } else {
                        stringToAdd = "";
                        stringToAdd += "\tcms_begin_class_var(cms,\"" + ovn_variable_name + "\");\n";
                        String temp_c_type = cpp_type;
                        if (temp_c_type.startsWith("struct ")) {
                            temp_c_type = temp_c_type.substring(7);
                        } else if (temp_c_type.startsWith("class ")) {
                            temp_c_type = temp_c_type.substring(6);
                        }
                        temp_c_type = StringFuncs.replace_white_space(temp_c_type);
                        stringToAdd += "\tcms_" + temp_c_type + "_update(cms, ( nml_" + temp_c_type + "_c_t *) &(x->" + variable_name + "));\n";
                        stringToAdd += "\tcms_end_class_var(cms,\"" + ovn_variable_name + "\");\n";
                        if (debug_on) {
                            DebugPrint("stringToAdd=" + stringToAdd);
                        }
                        type_info.C_UpdateFunction += stringToAdd;
                    }
                } else if (unbounded_array) {
                    if (!is_enum) {
                        stringToAdd = "\tcms_update_unbounded" + att_add + "_" + c_update_suffix + "(cms,\"" + ovn_variable_name + "\",&(x->" + variable_name + "), &(x->" + variable_name + "_length),&(x->" + variable_name + "_size_allocated));\n";
                        if (debug_on) {
                            DebugPrint("stringToAdd=" + stringToAdd);
                        }
                        type_info.C_UpdateFunction += stringToAdd;
                    } else {
                        System.err.println("Unbounded enumertions not supported with NML C interface");
                        stringToAdd = "#error Unbounded enumertions not supported with NML C interface\n";
                        if (debug_on) {
                            DebugPrint("stringToAdd=" + stringToAdd);
                        }
                        type_info.C_UpdateFunction += stringToAdd;
                    }

                } else if (is_enum) {
                    String enum_name = cpp_type;
                    int lastspaceindex = cpp_type.lastIndexOf(' ');
                    if (lastspaceindex > 0) {
                        enum_name = enum_name.substring(lastspaceindex + 1);
                    }
                    EnumTypeInfo enum_info = (EnumTypeInfo) ModuleInfo.m_enumInfoHashTable.get(enum_name);
                    if (enum_info != null && enum_info.Name != null) {
                        if (variable_name.startsWith("union_selector")) {
                            stringToAdd = "#error unions not supported in NML C interface\n";
                            if (debug_on) {
                                DebugPrint("stringToAdd=" + stringToAdd);
                            }
                            type_info.C_UpdateFunction += stringToAdd;
                            /*
                            type_info.C_UpdateFunction += "\tx->"+variable_name+"= ("+cpp_type+") cms->update_union_selector_with_name(\"";
                            type_info.C_UpdateFunction += variable_name+"\", (int)x->"+variable_name+",(void*)&(x->"+variable_name+"),&enum_"+enum_info.Name+"_info_struct);\n";
                            union_selector_var_name=variable_name;
                             */
                        } else {
                            stringToAdd = "";
                            if (!cpp_type.startsWith("enum ")) {
                                stringToAdd += "\tx->" + variable_name + "= (enum " + cpp_type + ") cms_update_enumeration(cms,\"";
                            } else {
                                stringToAdd += "\tx->" + variable_name + "= (" + cpp_type + ") cms_update_enumeration(cms,\"";
                            }
                            stringToAdd += ovn_variable_name + "\", (int)x->" + variable_name + ",(void*)&(x->" + variable_name + "),&enum_" + enum_info.Name + "_info_struct);\n";
                            if (debug_on) {
                                DebugPrint("stringToAdd=" + stringToAdd);
                            }
                            type_info.C_UpdateFunction += stringToAdd;
                        }
                    } else {
                        System.err.println("Could not get enumeration info for (" + enum_name + ")");

                    }
                } else {
                    stringToAdd = "\tcms_update_" + c_update_suffix + "(cms,\"" + ovn_variable_name + "\",&(x->" + variable_name + "));\n";
                    if (debug_on) {
                        DebugPrint("stringToAdd=" + stringToAdd);
                    }
                    type_info.C_UpdateFunction += stringToAdd;
                }
            }
            if (null != type_info.DerivedFrom) {
                stringToAdd =
                        "\n\tcms_end_class(cms,\"" + type_info.Name + "\",\"" + type_info.UnqualifiedDerivedFrom + "\");\n";
                if (debug_on) {
                    DebugPrint("stringToAdd=" + stringToAdd);
                }
                type_info.C_UpdateFunction += stringToAdd;
            } else {
                stringToAdd =
                        "\n\tcms_end_class(cms,\"" + type_info.Name + "\",0);\n";
                if (debug_on) {
                    DebugPrint("stringToAdd=" + stringToAdd);
                }
                type_info.C_UpdateFunction += stringToAdd;
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("Error Generating C++ Update function for " + type_info.Name);
            System.err.println("type_info.DerivedFrom = " + type_info.DerivedFrom);
            System.err.println("type_info.PreFinalPassInfo = " + type_info.PreFinalPassInfo);
            System.err.println("type_info.RawInfo = " + type_info.RawInfo);
            System.err.println("type_info.HiddenInfo = " + type_info.HiddenInfo);
            System.err.println("type_info.C_UpdateFunction = " + type_info.C_UpdateFunction);
            System.err.println("info_token = " + info_token);
            System.err.println("array_length_string = " + array_length_string);
            System.err.println("variable_name = " + variable_name);
            System.err.println("cpp_type = " + cpp_type);
            System.err.println("num_dims = " + num_dims);
            System.err.println("orig_info_token = " + orig_info_token);
            System.err.println("array_length = " + array_length);
            System.err.println("is_class = " + is_class);
        }
    }
}
